package mqtt

import (
	"context"
	"github.com/rs/zerolog"
	"sync"
	"time"
)

type (
	ClientID string

	Client struct {
		log      *zerolog.Logger
		ctx      context.Context
		cancel   context.CancelFunc
		clientId ClientID
		time     time.Time
		lock     sync.Mutex
		results  map[MsgID]*CmdReply
	}
)

func (c *Client) WriteReply(id MsgID, r *CmdReply) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.results[id] = r
}

func (c *Client) ReadReply(id MsgID) *CmdReply {
	c.lock.Lock()
	defer c.lock.Unlock()
	if r, ok := c.results[id]; ok {
		delete(c.results, id)
		return r
	}
	return nil
}

func (c *Client) expireReply() {
	c.lock.Lock()
	defer c.lock.Unlock()
	t := time.Now()
	for id, r := range c.results {
		if t.Sub(r.Time) > defaultReplyTtl {
			delete(c.results, id)
		}
	}
	c.log.Debug().Msgf("clientID[%s] 定时过期回复", c.clientId)
}

func (c *Client) clearReply() {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.results = make(map[MsgID]*CmdReply)

	c.log.Debug().Msgf("clientID[%s] 清空回复", c.clientId)
}

func (c *Client) start() {
	ticker := time.NewTicker(defaultReplyCycleDuration)
	defer ticker.Stop()

	for {
		select {

		case <-ticker.C: //定时清除过期回复信息
			c.expireReply()

		case <-c.ctx.Done(): //停止,清空回复信息
			c.clearReply()
			return
		}
	}
}

func newClient(ctx context.Context, log *zerolog.Logger, id ClientID) *Client {
	ctx, cancel := context.WithCancel(ctx)
	c := &Client{
		log:      log,
		ctx:      ctx,
		cancel:   cancel,
		clientId: id,
		time:     time.Now(),
		lock:     sync.Mutex{},
		results:  make(map[MsgID]*CmdReply),
	}
	go c.start()
	return c
}
